//
//  UIScrollView+Refresh.m
//  ToolHelper
//
//  Created by liaozhenming on 16/5/18.
//  Copyright © 2016年 liaozhenming. All rights reserved.
//

#import "UIScrollView+Refresh.h"
#import <objc/runtime.h>

@implementation UIScrollView (Refresh)

+ (void)load {
    
    Method dealloc = class_getInstanceMethod([self class], NSSelectorFromString(@"dealloc"));
    Method refresh_dealloc = class_getInstanceMethod([self class], @selector(refresh_dealloc));
    method_exchangeImplementations(dealloc, refresh_dealloc);
}

- (void)refresh_dealloc {
    
    if (self.kk_refreshEventHandle) {
        [self kk_removeObservers];
    }
    [self refresh_dealloc];
}


@dynamic kk_refreshEventHandle;
static const void *UIScrollViewDidRefreshEventHandleValue = &UIScrollViewDidRefreshEventHandleValue;
- (void)setKk_refreshEventHandle:(UIScrollViewDidRefreshEventHandle)refreshEventHandle {
    
    if (refreshEventHandle && self.kk_refreshEventHandle == nil) {
        [self kk_addObservers];
        [self initHeaderView];
    }
    
    objc_setAssociatedObject(self, UIScrollViewDidRefreshEventHandleValue, refreshEventHandle, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (UIScrollViewDidRefreshEventHandle)kk_refreshEventHandle {
    return objc_getAssociatedObject(self, UIScrollViewDidRefreshEventHandleValue);
}

@dynamic kk_loadingEventHandle;
static const void *UIScrollViewDidLoadingEventHandleValue = &UIScrollViewDidLoadingEventHandleValue;
- (void)setKk_loadingEventHandle:(UIScrollViewDidLoadingEventHandle)loadingEventHandle {
    
    if (loadingEventHandle) {
        [self initFooterView];
    }
    
    objc_setAssociatedObject(self, UIScrollViewDidLoadingEventHandleValue, loadingEventHandle, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (UIScrollViewDidLoadingEventHandle)kk_loadingEventHandle {
    return objc_getAssociatedObject(self, UIScrollViewDidLoadingEventHandleValue);
}

@dynamic kk_autoLoading;
static const void *UIScrollViewAutoLoadingValue = &UIScrollViewAutoLoadingValue;
- (void)setKk_autoLoading:(BOOL)kk_autoLoading {
    objc_setAssociatedObject(self, UIScrollViewAutoLoadingValue, @(kk_autoLoading), OBJC_ASSOCIATION_ASSIGN);
}
- (BOOL)kk_autoLoading {
    return [objc_getAssociatedObject(self, UIScrollViewAutoLoadingValue) boolValue];
}

@dynamic kk_refreshState;
static const void *UIScrollViewRefreshStateValue = &UIScrollViewRefreshStateValue;
- (void)setKk_refreshState:(UIScrollViewRefreshState)kk_refreshState {
    objc_setAssociatedObject(self, UIScrollViewRefreshStateValue, @(kk_refreshState), OBJC_ASSOCIATION_ASSIGN);
}
- (UIScrollViewRefreshState)kk_refreshState {
    return [objc_getAssociatedObject(self, UIScrollViewRefreshStateValue) unsignedIntegerValue];
}

@dynamic kk_settingInset;
static const void *UIScrollViewRefreshSettingInsetValue = &UIScrollViewRefreshSettingInsetValue;

- (UIEdgeInsets)kk_settingInset {
    id value = objc_getAssociatedObject(self, UIScrollViewRefreshSettingInsetValue);
    return value == nil ? UIEdgeInsetsZero : [value UIEdgeInsetsValue];
}

- (void)setKk_settingInset:(UIEdgeInsets)kk_settingInset {
//    [self setContentInset: kk_settingInset];
    objc_setAssociatedObject(self, UIScrollViewRefreshSettingInsetValue, [NSValue valueWithUIEdgeInsets: kk_settingInset], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@dynamic headerView;
static const void *UIScrollViewRefreshHeaderViewValue = &UIScrollViewRefreshHeaderViewValue;
- (UIScrollViewRefreshHeaderView *)headerView {
    return objc_getAssociatedObject(self, UIScrollViewRefreshHeaderViewValue);
}

- (void)setHeaderView:(UIScrollViewRefreshHeaderView *)headerView {
    objc_setAssociatedObject(self, UIScrollViewRefreshHeaderViewValue, headerView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}


@dynamic footerView;
static const void *UIScrollViewRefreshFooterViewValue = &UIScrollViewRefreshFooterViewValue;
- (UIScrollViewRefreshFooterView *)footerView {
    return objc_getAssociatedObject(self, UIScrollViewRefreshFooterViewValue);
}

- (void)setFooterView:(UIScrollViewRefreshFooterView *)footerView {
    
    objc_setAssociatedObject(self, UIScrollViewRefreshFooterViewValue, footerView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

#pragma mark -
#pragma mark - KVO methods

static CGFloat UIScrollviewScrollMaxOffsetY = 64.0f;

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    
    if ([keyPath isEqualToString: KVO_ContentOffset]) {
        
        if (self.kk_refreshState == UIScrollViewRefreshStateRefreshing) {
            return;
        }
        
        if (![self isDragging] && UIEdgeInsetsEqualToEdgeInsets(self.contentInset, [self kk_settingInset])) {
            
            NSValue* newPointValue = [change valueForKey: NSKeyValueChangeNewKey];
            CGFloat offsetY = [newPointValue CGPointValue].y;
            
            if (offsetY < self.kk_settingInset.top && self.kk_refreshEventHandle) {
                
                if (offsetY <= -(UIScrollviewScrollMaxOffsetY + self.kk_settingInset.top)) {
                    
                    [self setKk_refreshState: UIScrollViewRefreshStateRefreshing];
                    [self setContentInset: UIEdgeInsetsMake(UIScrollviewScrollMaxOffsetY + self.kk_settingInset.top, self.contentInset.left, self.contentInset.bottom, self.contentInset.right)];
                    [self.headerView startLoading];
                    
                    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                        //  重新加载
                        self.kk_refreshEventHandle();
                    });
                }
            }
            else if (offsetY > (self.contentSize.height - CGRectGetHeight(self.bounds)) && self.contentSize.height > CGRectGetHeight(self.bounds)) {
                
                if (offsetY > (self.contentSize.height - CGRectGetHeight(self.bounds) + UIScrollviewScrollMaxOffsetY) && self.kk_loadingEventHandle) {
                    
                    [self setKk_refreshState: UIScrollViewRefreshStateRefreshing];
                    [self setContentInset: UIEdgeInsetsMake(self.kk_settingInset.top, self.contentInset.left, UIScrollviewScrollMaxOffsetY, self.contentInset.right)];
                    [self.footerView startLoading];
                    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                        //  加载更多
                        self.kk_loadingEventHandle();
                    });
                }
            }
        }
    }
    else if ([keyPath isEqualToString: KVO_ContentSize]) {
        
        NSValue* contentSize = [change valueForKey: NSKeyValueChangeNewKey];
        CGFloat height = [contentSize CGSizeValue].height;
        
        self.footerView.hidden = height > CGRectGetHeight(self.bounds) ? NO : YES;
        [self.footerView setCenter: CGPointMake(CGRectGetWidth(self.footerView.bounds)/2, height + CGRectGetHeight(self.footerView.bounds)/2)];
    }
}

#pragma mark -
#pragma mark - Public methods
- (void)kk_reloadData {
    
    self.kk_refreshState = UIScrollViewRefreshStateNormal;
    
    [self.headerView stopLoading];
    [self.footerView stopLoading];
    
    if (!UIEdgeInsetsEqualToEdgeInsets(self.contentInset, [self kk_settingInset])) {
        
        [UIView animateWithDuration: 0.25 animations:^{
            [self setContentInset: [self kk_settingInset]];
        }completion:^(BOOL finished) {
            if ([self respondsToSelector: @selector(reloadData)]) {
                [self reloadData];
            }
        }];
    }
    else {
        if ([self respondsToSelector: @selector(reloadData)]) {
            [self reloadData];
        }
    }
}

#pragma mark - Private methods

static NSString* KVO_ContentOffset = @"contentOffset";
static NSString* KVO_ContentSize = @"contentSize";

- (void)kk_addObservers {
    
    [self addObserver: self forKeyPath: KVO_ContentOffset options: NSKeyValueObservingOptionNew context: nil];
    [self addObserver: self forKeyPath: KVO_ContentSize options: NSKeyValueObservingOptionNew context: nil];
    
    __weak typeof(self) weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        weakSelf.kk_settingInset = weakSelf.contentInset;
        weakSelf.contentInset = UIEdgeInsetsMake((UIScrollviewScrollMaxOffsetY + weakSelf.kk_settingInset.top), weakSelf.contentInset.left, weakSelf.contentInset.bottom, weakSelf.contentInset.right);
        [weakSelf setContentOffset: CGPointMake(0, -(UIScrollviewScrollMaxOffsetY + weakSelf.kk_settingInset.top)) animated: YES];
    });
}

- (void)kk_removeObservers {
    
    [self removeObserver: self forKeyPath: KVO_ContentOffset];
    [self removeObserver: self forKeyPath: KVO_ContentSize];
}

- (void)initHeaderView {
    
    UIScrollViewRefreshHeaderView *headerView = [UIScrollViewRefreshHeaderView createView];
    headerView.center = CGPointMake(CGRectGetWidth(headerView.bounds)/2, -CGRectGetHeight(headerView.bounds)/2);
    
    [self addSubview: headerView];
    
    [self setHeaderView: headerView];
}

- (void)initFooterView {
    
    UIScrollViewRefreshFooterView *footerView = [UIScrollViewRefreshFooterView createView];
    
    CGFloat height = self.contentSize.height;
    
    footerView.hidden = height > CGRectGetHeight(self.bounds) ? NO : YES;
    [footerView setCenter: CGPointMake(CGRectGetWidth(footerView.bounds)/2, height + CGRectGetHeight(footerView.bounds)/2)];
    
    [self addSubview: footerView];
    
    footerView.titleLabel.text = @"推荐更多中...";
    footerView.lastLoadingTime.hidden = true;
    
    [self setFooterView: footerView];
}

- (void)cleanAllSubViews {
    
    [self.headerView removeFromSuperview];
    [self.footerView removeFromSuperview];
}

- (void)reloadData {
    //  此类不实现功能,让子类去完成对应的操作
}


@end


@implementation UIScrollViewRefreshView

#pragma mark - Public methods

+ (instancetype)createView {
    
    UIScrollViewRefreshView *refreshView = [[UIScrollViewRefreshView alloc] initWithFrame: CGRectMake(0, 0, CGRectGetWidth([[UIScreen mainScreen] bounds]), 60)];
    
    UILabel *titleLabel = [[UILabel alloc] initWithFrame: CGRectMake(0, 0, CGRectGetWidth(refreshView.bounds), 20)];
    titleLabel.backgroundColor = [UIColor clearColor];
    titleLabel.textColor = [UIColor darkGrayColor];
    titleLabel.textAlignment = NSTextAlignmentCenter;
    titleLabel.font = [UIFont systemFontOfSize: 13];
    titleLabel.text = @"正在加载中...";
    titleLabel.center = CGPointMake(CGRectGetWidth(refreshView.bounds)/2 + 20, CGRectGetHeight(refreshView.bounds)/2 - 5);
    [refreshView addSubview: titleLabel];
    refreshView.titleLabel = titleLabel;
    
    UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleGray];
    activity.center = CGPointMake(CGRectGetWidth(refreshView.bounds)/2 - 35, CGRectGetHeight(refreshView.bounds)/2 - 5);
    activity.hidesWhenStopped = NO;
    [refreshView addSubview: activity];
    refreshView.loadingActivity = activity;
    
    UILabel *updateLabel = [[UILabel alloc] initWithFrame: CGRectMake(0, 0, CGRectGetWidth(refreshView.bounds), 20)];
    updateLabel.backgroundColor = [UIColor clearColor];
    updateLabel.textColor = [UIColor lightGrayColor];
    updateLabel.font = [UIFont systemFontOfSize: 13];
    updateLabel.textAlignment = NSTextAlignmentCenter;
    updateLabel.center = CGPointMake(CGRectGetWidth(refreshView.bounds)/2, CGRectGetHeight(refreshView.bounds)/2 + 15);
    [refreshView addSubview: updateLabel];
    refreshView.lastLoadingTime = updateLabel;
    
    [refreshView updateLoadingTime];
    
    return refreshView;
}

- (void)startLoading {
    
    _isLoading = true;
    
    [_loadingActivity startAnimating];
}

- (void)stopLoading {
    
    _isLoading = false;
    
    [_loadingActivity stopAnimating];
}

#pragma mark - Private methods

- (void)updateLoadingTime {
    
    self.lastLoadingTime.text = [NSString stringWithFormat: @"最后更新于:%@", [self getCurrentTime]];
}

- (NSString*)getCurrentTime {
    
    static NSDateFormatter *dateFormatter = nil;
    
    if (dateFormatter == nil) {
        
        dateFormatter = [NSDateFormatter new];
        [dateFormatter setDateFormat: @"yyyy-MM-dd HH:mm"];
    }
    
    return [dateFormatter stringFromDate: [NSDate date]];
}

@end


@implementation UIScrollViewRefreshHeaderView


@end


@implementation UIScrollViewRefreshFooterView


@end
